﻿using Microsoft.AspNetCore.Authentication.Cookies;
using MySql.Data.MySqlClient;
using SenGe.Application;
using SenGe.Infrastructure;
using System.Data;
using System.Reflection;
using Yitter.IdGenerator;

namespace SenGe.Web
{
    /// <summary>
    /// 项目服务扩展类
    /// </summary>
    public static class MyServicesExts
    {
        /// <summary>
        /// 配置项目服务
        /// </summary>
        /// <param name="builder"></param>
        public static void ConfigMyServices(this WebApplicationBuilder builder)
        {
            //使用依赖注入方式，为同一个请求只创建一个数据库连接服务
            builder.Services.AddScoped<IDbConnection>(provider =>
            {
                var connection = builder.Configuration.GetConnectionString("default");
                if (connection == null) throw new InvalidOperationException("未配置数据库连接字符串！");
                return new MySqlConnection(connection);
            });

            //使用依赖注入方式，注入仓储层
            builder.Services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
            Assembly assembly = Assembly.Load("SenGe.Infrastructure");
            Type typeBaseRepository = typeof(IBaseRepository<>);
            List<TypeInfo> implementedList = assembly.DefinedTypes.Where(t => t.IsClass
                                && t.IsPublic
                                && !t.IsAbstract
                                && !t.IsGenericType
                                && t != typeBaseRepository
                                && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeBaseRepository)
                               ).ToList();
            foreach (TypeInfo implementedItem in implementedList)
            {
                foreach (Type implementedInterface in implementedItem.ImplementedInterfaces)
                {
                    if (implementedInterface.IsGenericType) continue;
                    builder.Services.AddScoped(implementedInterface, implementedItem);
                }
            }
            //使用依赖注入方式，注入服务层
            builder.Services.AddScoped(typeof(IBaseService), typeof(BaseService));
            assembly = Assembly.Load("SenGe.Application");
            Type typeBaseService = typeof(IBaseService);
            implementedList = assembly.DefinedTypes.Where(t => t.IsClass
                                && t.IsPublic
                                && !t.IsAbstract
                                && !t.IsGenericType
                                && t != typeBaseService
                                && t.GetInterfaces().Any(i => i.GetInterfaces().Any(j => j == typeBaseService))
                               ).ToList();
            foreach (TypeInfo implementedItem in implementedList)
            {
                foreach (Type implementedInterface in implementedItem.ImplementedInterfaces)
                {
                    if (implementedInterface.IsGenericType || implementedInterface == typeBaseService) continue;
                    builder.Services.AddScoped(implementedInterface, implementedItem);
                }
            }

            //设置雪花Id配置
            var options = new IdGeneratorOptions
            {
                WorkerId = 1,          // 机器ID，必须唯一（0-63）
                WorkerIdBitLength = 6, // WorkerId 位数，默认 6 位
                SeqBitLength = 6,      // 序列号位数，默认 6 位
                Method = 1             // 算法类型，1 为漂移算法
            };
            YitIdHelper.SetIdGenerator(options);

            // 添加认证服务
            builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                {
                    options.Cookie.Name = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.Cookie.HttpOnly = true;
                    options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                    options.LoginPath = "/Account/Login";
                    options.LogoutPath = "/Account/Logout";
                    options.SlidingExpiration = true;
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                });
        }
    }
}
